package cc.cix.gt.org.service.impl;

import cc.cix.gt.common.constant.StringConstant;
import cc.cix.gt.common.entity.ResultPage;
import cc.cix.gt.common.exception.SystemException;
import cc.cix.gt.common.util.SystemUtil;
import cc.cix.gt.common.util.JwtTokenUtil;
import cc.cix.gt.common.util.SortUtil;
import cc.cix.gt.common.util.ValidateCodeUtil;
import cc.cix.gt.org.dto.query.QueryUserReq;
import cc.cix.gt.org.dto.request.LoginReq;
import cc.cix.gt.org.dto.response.LoginResp;
import cc.cix.gt.org.entity.*;
import cc.cix.gt.org.enums.UserSex;
import cc.cix.gt.org.enums.UserStatus;
import cc.cix.gt.org.mapper.UserMapper;
import cc.cix.gt.org.service.*;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author cix
 */
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements IUserService {

    private final IUserRoleService userRoleService;
    private final IDeptService deptService;
    private final PasswordEncoder passwordEncoder;
    private final IUserDataPermissionService userDataPermissionService;
    private final IRoleService roleService;
    private final JwtTokenUtil jwtTokenUtil;
    private final IMenuService menuService;
    private final ILoginLogService loginLogService;

    @Value("${gt.debug}")
    private boolean debug;

    @Override
    public LoginResp login(HttpServletRequest request, LoginReq dto) {
        // 验证码是否正确
        if (!debug) {
            ValidateCodeUtil.check(dto.getKey(), dto.getVerifyCode());
        }

        // 用户是否存在
        User user = lambdaQuery().eq(User::getMobile, dto.getMobile()).one();
        if (ObjectUtil.isNull(user)) {
            throw new SystemException("用户不存在");
        }

        // 密码是否正确
        boolean matches = passwordEncoder.matches(dto.getPassword(), user.getPassword());
        if (!matches) {
            throw new SystemException("用户名或密码错误");
        }

        return loginSuccess(request, user);
    }

    @Override
    public ResultPage<User> listUser(QueryUserReq dto) {
        User currentUser = BeanUtil.toBean(dto, User.class);
        QueryWrapper<User> wrapper = new QueryWrapper<>(currentUser)
                .inSql(ObjectUtil.isNotNull(currentUser.getDeptName()), "dept_id",
                        "SELECT id FROM t_dept WHERE dept_name = " + currentUser.getDeptName());
        SortUtil.handleWrapperSort(dto, wrapper);

        IPage<User> userPage = page(new Page<>(dto.getPageNum(), dto.getPageSize()), wrapper);
        userPage.getRecords().forEach(user -> {
            Dept dept = deptService.lambdaQuery().eq(Dept::getId, user.getDeptId()).one();
            user.setDeptName(Optional.ofNullable(dept).map(Dept::getDeptName).orElse("无"));

            // 获取部门数据权限列表
            List<UserDataPermission> userDataPermissions = userDataPermissionService.lambdaQuery()
                    .eq(UserDataPermission::getUserId, user.getId())
                    .list();
            List<Long> deptIds = userDataPermissions.stream()
                    .map(UserDataPermission::getDeptId)
                    .collect(Collectors.toList());
            user.setDeptIds(deptIds);

            // 获取角色列表
            List<UserRole> userRoles = userRoleService.lambdaQuery().eq(UserRole::getUserId, user.getId()).list();
            List<Long> roleIds = userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList());
            Role role = roleService.query()
                    .select("GROUP_CONCAT(role_name) roleName")
                    .in("id", roleIds)
                    .one();

            user.setRoleIds(roleIds);
            user.setRoleName(role.getRoleName());
        });

        return SystemUtil.getPage(userPage);
    }

    @Override
    public User getUserByMobile(String mobile) {
        return lambdaQuery().eq(User::getMobile, mobile).one();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createUser(User user) throws SystemException {
        // 创建用户
        user.setPassword(passwordEncoder.encode(user.getPassword()));

        save(user);

        // 保存用户角色
        setUserRoles(user, user.getRoleIds());

        // 保存用户数据权限关联关系
        setUserDataPermissions(user, user.getDeptIds());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(User user) {
        // 如果存在密码
        if (ObjectUtil.isNotNull(user.getPassword())) {
            user.setPassword(passwordEncoder.encode(user.getPassword()));
        }

        // 更新用户
        user.setMobile(null);
        user.setCreateTime(null);
        updateById(user);

        userRoleService.lambdaUpdate().eq(UserRole::getUserId, user.getId()).remove();
        setUserRoles(user, user.getRoleIds());

        userDataPermissionService.lambdaUpdate().eq(UserDataPermission::getUserId, user.getId()).remove();
        setUserDataPermissions(user, user.getDeptIds());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteUserByIds(List<String> userIds) {
        removeByIds(userIds);

        // 删除用户角色
        userRoleService.lambdaUpdate().in(UserRole::getUserId, userIds).remove();
        userDataPermissionService.lambdaUpdate().in(UserDataPermission::getUserId, userIds).remove();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProfile(User user) throws SystemException {
        // 如果存在密码
        if (ObjectUtil.isNotNull(user.getPassword())) {
            user.setPassword(passwordEncoder.encode(user.getPassword()));
        }

        if (isCurrentUser(user.getId())) {
            updateById(user);
        } else {
            throw new SystemException("您无权修改别人的账号信息！");
        }
    }

    @SneakyThrows
    @Override
    public void registerUser(User user) {
        // 默认设置
        List<Long> roleIds = roleService.lambdaQuery().eq(Role::getRoleName, "普通用户").list().stream()
                .map(Role::getId)
                .collect(Collectors.toList());

        user.setStatus(UserStatus.VALID.getValue());
        user.setRoleIds(roleIds);
        user.setSex(UserSex.FEMALE.getValue());
        user.setUsername(user.getMobile());

        // 创建用户
        createUser(user);
    }

    @Override
    public void updatePassword(String password) {
        lambdaUpdate()
                .eq(User::getUsername, SystemUtil.getCurrentUser().getUsername())
                .set(User::getPassword, passwordEncoder.encode(password))
                .update();
    }

    @Override
    public void resetPassword(String username) {
        lambdaUpdate()
                .in(User::getUsername, StrUtil.splitTrim(username, StringConstant.COMMA))
                .set(User::getPassword, passwordEncoder.encode(User.DEFAULT_PASSWORD))
                .update();
    }

    private void setUserRoles(User user, List<Long> roleIds) {
        if (CollUtil.isEmpty(roleIds)) {
            return;
        }

        List<UserRole> userRoles = new ArrayList<>();
        roleIds.forEach(roleId -> {
            UserRole userRole = new UserRole();
            userRole.setUserId(user.getId());
            userRole.setRoleId(roleId);
            userRoles.add(userRole);
        });
        userRoleService.saveBatch(userRoles);
    }

    private void setUserDataPermissions(User user, List<Long> deptIds) {
        if (CollUtil.isEmpty(deptIds)) {
            return;
        }

        List<UserDataPermission> userDataPermissions = new ArrayList<>();
        deptIds.forEach(deptId -> {
            UserDataPermission permission = new UserDataPermission();
            permission.setDeptId(deptId);
            permission.setUserId(user.getId());
            userDataPermissions.add(permission);
        });
        userDataPermissionService.saveBatch(userDataPermissions);
    }

    private boolean isCurrentUser(Long id) {
        return Optional.ofNullable(SystemUtil.getCurrentUser()).map(user -> ObjectUtil.equals(id, user.getId())).orElse(false);
    }

    /**
     * 成功登录处理
     *
     * @param user 用户
     * @return token
     */
    private LoginResp loginSuccess(HttpServletRequest request, User user) {
        // 获取权限列表
        List<String> menus = menuService.listUserMenu(user.getUsername()).stream()
                .map(Menu::getPerms)
                .collect(Collectors.toList());

        // 创建 token
        String token = jwtTokenUtil.createToken(user.getId().toString(), menus);

        // 更新最后登录时间
        lambdaUpdate()
                .eq(User::getUsername, user.getUsername())
                .set(User::getLastLoginTime, LocalDateTime.now())
                .update();

        // 保存登录日志
        LoginLog loginLog = new LoginLog();
        loginLog.setUsername(user.getUsername());
        loginLog.setSystemBrowserInfo(request.getHeader("user-agent"));
        loginLogService.saveLoginLog(loginLog);

        return LoginResp.builder().token(token).build();
    }


}
